home *** CD-ROM | disk | FTP | other *** search
/ SuperHack / SuperHack CD.bin / CODING / MISC / RADIX.ZIP / RADIX.TXT
Encoding:
Text File  |  1997-01-09  |  5.9 KB  |  223 lines

  1. Hi.
  2.  
  3. This is a short tutorial on the radix-sort. If you already know what a radix-sort
  4. is, how it works and you don't use quicksort anymore you can skip this
  5. tutorial.
  6.  
  7. The tutorial is intended for programmers who have to write a fast sorting
  8. algorithm for small- and medium-sized lists. So if you want to sort a
  9. database you should search the web for another tutorial. However, if you
  10. write a 3d-engine or such stuff you should read on because radix-sort is very
  11. good for this purpose.
  12.  
  13.  
  14. THE BASICS
  15. ----------
  16.  
  17.   How do you sort a list of numbers? Basically you have an algorithm which
  18.   compares numbers and tries to get the list more and more sorted.
  19.  
  20.   The Radix-sort is a little bit different. It doesn't compare anything, it
  21.   sorts the numbers with several passes.
  22.  
  23.   Let's start with a list of bytes. A very simple radix-sort for bytes
  24.   would work like this:
  25.  
  26.   source:     List of bytes
  27.   source_n:   number of bytes to sort
  28.   dest[256]:  256 lists of bytes. each list should have enough space to hold
  29.                 source_n elements.
  30.  
  31.   Here is pseudo-code to sort the list:
  32.  
  33.   for i = 0 to source_n do
  34.     dest[source[i]].append (source[i])
  35.   endfor
  36.  
  37.   This means you append all items with value #1 to list 1, all items with
  38.   value #2 to list 2 and so on. As you can see this algorithm runs very fast
  39.   (it only copies the bytes in a very tight loop). The disadvantage is that
  40.   you need a lot of memory to sort the list becuase you don't know how many
  41.   items of each type you have...
  42.  
  43.  
  44.  
  45. SAVING MEMORY
  46. -------------
  47.  
  48.   Do you really not know how many items of each type you have? No, you can
  49.   count them and optimize your memory requirements. We'll need another loop
  50.   to count the distribution of the source values:
  51.  
  52.   int distribution[256]
  53.  
  54.   // fill the list with zeros.
  55.  
  56.   for i=0 to 255  do
  57.      distribution[i]=0;
  58.  
  59.   // build a distribution history:
  60.  
  61.   for i=0 to source_n do
  62.      distribution[source[i]] =  distribution[source[i]] +1;
  63.   endfor
  64.  
  65.   // Now we build an index-list for each possible element:
  66.  
  67.   int index[256];
  68.   index [0]=0;
  69.  
  70.   for i=0 to 255 do
  71.     index[i]=index[i-1]+distribution[i-1];
  72.   endfor
  73.  
  74.  
  75.   Adapting the original radix-sort to make use of the new information
  76.   will result in this code:
  77.  
  78.   dest: array of bytes with space for source_n bytes.
  79.  
  80.   for i = 0 to source_n do
  81.     dest[index[source[i]]]=source[i];
  82.     index[source[i]] = index[source[i]] + 1;
  83.   endfor
  84.  
  85.   After this dest contains the sorted bytes.
  86.  
  87.   Now we only need the same amount of memory as the original source list
  88.   took up. This saves quite a lot of memory, and if your lists don't contain
  89.   millions of values we can live with the memory requirements.
  90.  
  91.  
  92. EXTENDING THE BYTE-SORT
  93. -----------------------
  94.  
  95.   Who wants to sort bytes? You? I normally sort ascii text, floats or
  96.   long ints. Because I only want to explain how the extension works, I'll
  97.   go on with long ints.
  98.  
  99.   You can increase the size of the elements in the sort in several ways.
  100.   You can either increase the size of index and distribution or you sort in
  101.   several passes.
  102.  
  103.   Increasing the size of the index only works for short values (sorting
  104.   short ints would require at least 65536*2 bytes for the index and
  105.   distribution lists, which finally need 256 kb of memory... I think this is
  106.   too much (just think about how long it takes to clear the memory and build
  107.   the index-list.. In this time a quick sort may have sorted your list
  108.   already).
  109.  
  110.   Now we need a clever way to sort more bits with the same memory amount.
  111.  
  112.   We can do this with several passes. Let's do it in decimal.
  113.  
  114.   Unsorted list:
  115.  
  116.   523
  117.   153
  118.   088
  119.   554
  120.   235
  121.  
  122.   Sorted for Radix 0 (least significant digit):
  123.  
  124.   523
  125.   153
  126.   554
  127.   235
  128.   088
  129.     ^
  130.  
  131.   Sorted for Radix 1 (2nd. significant digit):
  132.  
  133.   523
  134.   235
  135.   153
  136.   554
  137.   088
  138.    ^
  139.  
  140.   Sorted for Radix 2 (most. significant digit):
  141.  
  142.   088
  143.   153
  144.   235
  145.   523
  146.   554
  147.   ^
  148.  
  149.   As you can se we preserve the old sorting order and advance by one digit
  150.   until we've sorted all digits. The illustration did this in decimal. The
  151.   native digit format for computers are bits, bytes, words and dwords.
  152.  
  153. C Source
  154. --------
  155.  
  156.  I know... real programmers code in assembler. (Hey! I thought you want to
  157.  understand the radix-sort, not assembly). The program compiles well under
  158.  Watcom C++. However, it should at least work on all 32-bit C compilers and
  159.  on some 16-bit compilers.
  160.  
  161.  
  162.  
  163.  ----------------------------- cut here ---------------------------
  164.  
  165. #include <iostream.h>
  166. #include <stdlib.h>
  167. #include <string.h>
  168.  
  169. void radix (int byte, long N, long *source, long *dest)
  170. {
  171.   long count[256];
  172.   long index[256];
  173.   memset (count, 0, sizeof (count));
  174.   for ( int i=0; i<N; i++ ) count[((source[i])>>(byte*8))&0xff]++;
  175.  
  176.   index[0]=0;
  177.   for ( i=1; i<256; i++ ) index[i]=index[i-1]+count[i-1];
  178.   for ( i=0; i<N; i++ ) dest[index[((source[i])>>(byte*8))&0xff]++] = source[i];
  179. }
  180.  
  181. void radixsort (long *source, long *temp, long N)
  182. {
  183.   radix (0, N, source, temp);
  184.   radix (1, N, temp, source);
  185.   radix (2, N, source, temp);
  186.   radix (3, N, temp, source);
  187. }
  188.  
  189. void make_random (long *data, long N)
  190. {
  191.   for ( int i=0; i<N; i++ ) data[i]=rand()|(rand()<<16);
  192. }
  193.  
  194.  
  195. long data[100];
  196. long temp[100];
  197.  
  198. void main (void)
  199. {
  200.  make_random(data, 100);
  201.  radixsort (data, temp, 100);
  202.  for ( int i=0; i<100; i++ ) cout << data[i] << '\n';
  203. }
  204.  
  205.  ----------------------------- cut here ---------------------------
  206.  
  207. LAST WORDS
  208. ----------
  209.  
  210.  I hope you learned something.
  211.  
  212.  I have to thank Climax from Amable for making me interested in this
  213.  algorithm (well, two weeks before I thought quick sort is the best).
  214.  
  215.  Also thanks go out to Peter Flynn who took a look at this file and
  216.  corrected all my type-erros. Thank you!
  217.  
  218.  If you want to contact me write to
  219.  
  220.   Nils Pipenbrinck / Submissive from Cubic Team & $eeN
  221.   100121.2450@compuserve.com (checked daily)
  222.   subcode@tecs.de (checked at least once a week)
  223.